\section {Ejercicio 1}

	\subsection{Introducción}

		Este ejercicio consistió en la implementación de un perceptrón simple,
		con el objetivo de discernir ciertos patrones de datos, representados
		por grillas booleanas de $5x5$ valores, cada uno de los cuáles
		representaba el dibujo de una letra mayúscula.

		El trabajo del perceptrón era responder a que letra particular se
		parecía más el dibujo.

	\subsection{Explicación}

		Los algoritmos implementados fueron los de evaluación de un
		conjunto de patrones de entrada, y el algoritmo de adaptación
		de la matriz de pesos para un conjunto de entrenamiento.

		

		\subsubsection{Conjuntos de datos}

			Los conjuntos de entrenamiento, validación y testeo fueron patrones
			que representaban a las 26 letras del abecedario.

			En algunos patrones se insertaron ruidos aleatorios para analizar
			la respuesta del perceptrón ante pequeñas variaciones en los mismos.
			Se generaron, sobre el set sin ruido, 5 distintos sets, en los
			cuáles en el set $i$ cada letra tiene entre $1$ e $i$ valores
			flipeados (ruidosos). Más adelante nos referimos a ellos
			como conjuntos con error de orden $i$.

			Se probaron varios sets como conjunto de entrenamiento,
			excepto los de mayor ruido (no tenía demasiado sentido porque los
			patrones ya no eran lo suficientemente representativos)
			y se usaron también como conjuntos de testing para distintas
			pruebas. Como conjunto de validación, usamos los mismos
			conjuntos de entrenamiento.
		 
		\subsubsection{Algoritmo}

			El algoritmo de Evaluación, para cada patrón \textbf{p}
			$\in \mathbb{B}^{R}$, depende de la matriz de pesos
			\textbf{W} $\in \mathbb{R}^{RxS}$ y del vector de Bias
			\textbf{b} $\in \mathbb{R}^{S}$, el vector de solución
			\textbf{O} $\in \mathbb{B}^{S}$ y la función de activación
			que en nuestro caso es la función escalonada
			\textit{hardlim} definida como
%			$$ hardlim(n) = \lbrace \eq $$
			\begin{equation*}
			hardlim(n) =
			\begin{cases}
				0 & \text{si $n<0$} \\
				1 & \text{sino}
			\end{cases}
			\end{equation*}
			La solución se calcula de la siguiente manera:
			$$ \textbf{O} = hardlim( \textbf{W}\textbf{p} + \textbf{b} ) $$

	\subsection{Detalles de implementación}

		La implementación fue realizada en el lenguaje \texttt{Python}
		ya que tiene definidos los tipos de datos de Matrices y
		Vectores y las operaciones básicas necesarias para operar con
		ellos. Para facilitar ésto se usó la librería \texttt{Numpy}.

		Además se uso la librería \texttt{Random} para la generación
		de los números aleatorios.

	\subsection{Pruebas y Resultados}

		\subsubsection{Elección y generación}

			\textbf{Elección de parámetros óptimos}

			Las primeras pruebas fueron hechas para elegir una buena velocidad
			de aprendizaje para el algoritmo.

			La velocidad de aprendizaje la elegimos en el intervalo
			$(0,3.0)$, con una granularidad de $0.1$. Elegimos este
			intervalo porque usualmente la velocidad de aprendizaje se
			encuentra entre $0$ y $1$, y además queríamos ver como se
			comportaba el algoritmo con velocidades superiores a $1$.
			% HABLAR SOBRE SOLUCIONES BINARIAS 0-1

			Para cada una de estas velocidades, se corrió 10 veces el
			algoritmo de aprendizaje con 10 distintas matrices de pesos
			iniciales, generadas con pesos aleatorios entre $0$ y $1$
			(distribución uniforme). Las semillas para el generador de
			números aleatorios son las mismas para cada velocidad, para
			asegurar igualdad de condiciones en los experimentos.

			Los datos representativos que se tuvieron en cuenta para
			calificar cada instancia del algoritmo, fueron los
			promedios y mínimos absolutos del error mínimo y la
			iteración donde éste fue encontrado. Cuando hablamos de
			error en este caso, hablamos de la suma de los errores
			cuadráticos medios de cada patrón en el conjunto de
			validación (que en nuestro caso es el mismo que el conjunto
			de entrenamiento).

			\textbf{Testeo}

			Calculados los parámetros considerados óptimos para el
			algoritmo, pasamos a la fase de testeo del algoritmo,
			en la cuál evaluamos los resultados del Perceptrón sobre
			conjuntos de datos, distintos del conjunto con el que fue
			entrenado.

		\subsubsection{Resultados}

			El siguiente cuadro muestra los resultados obtenidos de
			los experimentos realizados para encontrar los mejores
			parámetros.

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.75]{img/ej1/Error_lr.png}
				\caption{
					Este es el error obtenido por el algoritmo de
					aprendizaje, para un cojunto de testing de 26
					patrones (set completo) para cada una de las velocidades de
					aprendizaje evaluadas.
				}
				\label{fig:Error}
			\end{figure}

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.75]{img/ej1/Iteracion_lr.png}
				\caption{
					El gráfico muestra la primera iteración para la
					cuál el algoritmo encontró el error mínimo
					graficado en la figura~\ref{fig:Error}.
				}
				\label{fig:Iteracion}
			\end{figure}

			El siguiente gráfico muestra los resultado de las pruebas
			realizadas para comparar la convergencia de las curvas
			del error de cada instancia del algoritmo variando las
			velocidades de adaptación. Las mismas varían entre $0$ y
			$1$, ya que despúes del experimento anterior vimos que para
			valores más altos que uno, el error no mejora sino que
			tiende a oscilar alrededor de un límite, y la iteración
			donde se encuentra el error mínimo tiende a aumentar.

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.55]{img/ej1/Convergencia.png}
				\caption{
					El error cuadrático medio mínimo en todos los casos resulto
					ser exactamente $0.3$. Las épocas en que el algoritmo
					alcanzo dicha cota se pueden ver en la leyenda
					correspondiente en el gráfico.
				}
				\label{fig:Convergencia}
			\end{figure}

			Como se puede apreciar en la firgura \ref{fig:Convergencia}, la
			velocidad de adaptación que mas rápido parece converger es $0.1$.
			También cabe mencionar que a partir de las $400$ iteraciones, el
			error del algoritmo parece oscilar en una pequeña region
			cerca de la cota mínima, y que el análisis del comportamiento mas
			allá de esta cota probablemente no aporte ninguna información nueva.

			Los siguientes son los resultados obtenidos de evaluar el
			Perceptrón entrenado en la fase de testeo.

			Como medida de referencia, podemos tomar el $ECM_a$
			(Error cuadrático medio absoluto) del algoritmo para cada
			conjunto de testeado. En la tabla arriba de cada gráfico
			aparece en negrita el conjunto que se tomo como conjunto
			de entrenamiento correspondiente. \\
\newpage
			\begin{center}

				\textbf{Entrenamiento del Perceptrón con un conjunto sin ruido}

				\begin{tabular}{|l|c|c|c|c|c|c|}
					\hline
					conjunto	& $\textbf{test}$	& $test_1$	& $test_2$	& $test_3$	& $test_4$	& $test_5$ \\
					\hline
					$ECM_a$			& $\textbf{0.04}$	& $0.21$	& $0.42$	& $0.54$	& $0.71$	& $0.77$ \\
					\hline
				\end{tabular}

			\end{center}

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.55]{img/ej1/PerceptronEntrenadoSinRuido.png}
				\caption{
					La figura muestra los resultados arrojados por el
					perceptrón entrenado con un conjunto sin ruido.
					Los números en los ejes indican el índice de la
					letra representada, donde estas están ordenadas
					por orden alfabético.
					Los conjuntos de testing $test_i$ hacen
					referencia al conjunto de testeo resultante de
					aplicar $i$ puntos de ruido en cada patrón a
					su análogo sin ruido.
				}
				\label{fig:ResRuido}
			\end{figure}

			Vemos en la figura~\ref{fig:ResRuido} como disminuye la
			efectividad del Perceptrón a medida que aumenta el ruido
			en los patrones.
			Para patrones de entrada con poco ruido, sin embargo el
			algoritmo parece funcionar medianamente bien. Véanse por
			ejemplo los resultados de $test_1$.

\newpage
			\begin{center}

				\textbf{Entrenamiento del Perceptrón con un conjunto con ruido de grado 1}

				\begin{tabular}{|l|c|c|c|c|c|c|}
					\hline
					conjunto	& $test$	& $\textbf{test}_1$	& $test_2$	& $test_3$	& $test_4$	& $test_5$ \\
					\hline
					$ECM_a$			& $0.33$	& $\textbf{0.00}$	& $0.27$	& $0.65$	& $0.75$	& $0.75$ \\
					\hline
				\end{tabular}

			\end{center}

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.55]{img/ej1/PerceptronEntrenadoConRuido1.png}
				\caption{
					La figura muestra los resultados arrojados por el
					perceptrón entrenado con un conjunto con ruido de grado 1.
					Los números en los ejes indican el índice de la
					letra representada, donde estas están ordenadas
					por orden alfabético.
					Los conjuntos de testing $test_i$ hacen
					referencia al conjunto de testeo resultante de
					aplicar $i$ puntos de ruido en cada patrón a
					su análogo sin ruido ($test$).
				}
				\label{fig:ResRuido1}
			\end{figure}

			Aquí vemos como, a medida que ingresamos ruido en el
			entrenamiento del Perceptrón, las soluciónes se van haciendo
			mas dispersas e imprecisas.

			Este tipo de entrenamiento podría usarse si estamos seguros
			que en el contexto de uso nos vamos a encontrar información
			con bastante ruido como
			entrada, ya que no tiende necesariamente a una solución
			perfecta, y soluciónes con ruido alto tienen un error mucho
			más bajo.

\newpage
			\begin{center}

				\textbf{Entrenamiento del Perceptrón con un conjunto con ruido de grado 2}

				\begin{tabular}{|l|c|c|c|c|c|c|}
					\hline
					conjunto	& $test$	& $test_1$	& $\textbf{test}_2$	& $test_3$	& $test_4$	& $test_5$ \\
					\hline
					ECM			& $0.42$	& $0.27$	& $\textbf{0.00}$	& $0.67$	& $0.71$	& $0.70$ \\
					\hline
				\end{tabular}

			\end{center}

			\begin{figure}[H]
				\centering
				\noindent\includegraphics[scale=0.55]{img/ej1/PerceptronEntrenadoConRuido2.png}
				\caption{
					La figura muestra los resultados arrojados por el
					perceptrón entrenado con un conjunto con ruido de grado 2.
					Los números en los ejes indican el índice de la
					letra representada, donde estas están ordenadas
					por orden alfabético.
					Los conjuntos de testing $test_i$ hacen
					referencia al conjunto de testeo resultante de
					aplicar $i$ puntos de ruido en cada patrón a
					su análogo sin ruido ($test$).
				}
				\label{fig:ResRuido2}
			\end{figure}

			Aquí vemos que ya para un entrenamiento con bastante ruido
			(grado 2), la precisión del Perceptron fuera del mismo
			conjunto de entrenamiento no es nada buena. Y esto
			claramente empeora a medida que nos alejamos de la solución
			exacta (sin ruido) como conjunto de entrenamiento.

\newpage
	\subsection{Conclusiones}

		Encontramos valores para los parámetros de entrenamiento
		del Perceptrón que nos permitieron entrenar al mismo de una
		manera (mas o menos) óptima para realizar la tarea para la
		cuál fue desarrollado.

		En cuanto a la velocidad de aprendizaje elegimos $0.1$ ya que
		es la velocidad para la cuál el algoritmo encuentra más rápido
		el error mínimo en todos los casos de prueba (además vemos que
		se acerca más rápidamente al mismo), así como también produce
		el mínimo error promedio.

		Luego, corrimos conjuntos de entradas de testing para distintos
		conjuntos de entrenamiento para analizar como se comportaban
		los mismos y que errores y en que medida los cometían.

		En general sobre el ejercicio, podemos concluír que los
		resultados obtenidos son bastante malos, si el
		contexto en el que se da el problema requiere de una buena
		precisión.

		Tal vez una arquitectura con más potencial que el Perceptrón simple
		permita lograr mejores resultados que éstos.

		El mayor problema que nosotros vimos en este ejercicio, es la cantidad
		de información que es recibida como entrada por el Perceptrón.
		Probablemente al aumentar la cantidad de puntos de la grilla
		consigamos mejorar bastante la calidad de la salida.
